﻿
using Mengsk.ProxyDelivery.Domain;
using Mengsk.ProxyDelivery.HTTPHelpers;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Windows;

namespace Mengsk.ProxyDelivery.Service.Delivery
{
    public class DeliveryService
    {
        static string[] companies = null;
        const string APIURL = "http://www.kuaidi100.com/query";
        const string APPCODE = "e652b80bcaf24ff5";
        private static Dictionary<string, string> companyCodes = new Dictionary<string, string>();
        private static Dictionary<string, string> para = new Dictionary<string, string>();
        private static DataContractJsonSerializer sizeSer = new DataContractJsonSerializer(typeof(Kuaidi100DeliveryResult));
        private static Random r = new Random(456456);

        private static List<IDeliveryMoneyComputer> computers = new List<IDeliveryMoneyComputer>();

        static DeliveryService()
        {
            companyCodes["百世汇通"] = "huitongkuaidi";
            companyCodes["EMS"] = "ems";
            companyCodes["EMS经济快递"] = "ems";
            companyCodes["天天快递"] = "tiantian";
            companyCodes["邮政小包"] = "youzhengguonei";
            companyCodes["宅急送"] = "zhaijisong";
            companyCodes["韵达快递"] = "yunda";
            companyCodes["顺丰速运"] = "shunfeng";
            companyCodes["圆通速递"] = "yuantong";
            companyCodes["全峰快递"] = "quanfengkuaidi";
            companyCodes["优速快递"] = "youshuwuliu";
            companyCodes["中通速递"] = "zhongtong";
            companyCodes["申通快递"] = "shentong";
            companyCodes["国通快递"] = "guotongkuaidi";
            companyCodes["快捷快递"] = "kuaijiesudi";
            companyCodes["速尔快递"] = "suer";
            companyCodes["龙邦物流"] = "longbanwuliu";
            companyCodes["德邦物流"] = "debangwuliu";
            companyCodes["全一快递"] = "quanyikuaidi";
            companyCodes["如风达快递"] = "rufengda";
            para["key"] = APPCODE;

            computers.Add(new YTOCodComputer());
            computers.Add(new YTOComputer());
            computers.Add(new YZXBComputer());
            computers.Add(new ZJSCodComputer());
        }

        public static string[] GetDeliveryCompanies()
        {
            if (companies != null)
            {
                return companies;
            }

            companies = new string[]
            {
                "韵达快递",
                "圆通速递",
                "申通快递",
                "中通速递",
                "国通快递",
                "EMS经济快递",
                "宅急送",
                "顺丰速运",
                "百世汇通",
                "天天快递",
                "邮政小包",
                "全峰快递",
                "优速快递",
                "速尔快递",
                "快捷快递",
                "龙邦物流",
                "增益速递",
                "德邦物流",
                "全一快递",
                "如风达快递"
            };
            return companies;
        }

        public static DeliveryTransation Query(string company, string number)
        {
            if (companyCodes.ContainsKey(company) == false)
            {
                throw new Exception("未能找到对应的快递公司");
            }

            String code = companyCodes[company];
            para["type"] = code;
            para["postid"] = number;
            para["temp"] = "0." + r.Next() + "" + r.Next();
            String content = MSHttpRestful.DoWithRetry(() => MSHttpRestful.PostUrlEncodeBodyReturnString(APIURL, para, Encoding.UTF8));
            Byte[] bytes = Encoding.UTF8.GetBytes(content);
            var ret = sizeSer.ReadObject(new MemoryStream(bytes, false)) as Kuaidi100DeliveryResult;

            var item = new Domain.DeliveryTransation();
            item.IsSigned = ret.ischeck == "1" ? true : false;
            if (ret.message.ToUpper().Equals("OK") == false)
            {
                throw new Exception(ret.message);
            }
            item.Items = new List<DeilveryTransationItem>();
            foreach (var o in ret.data)
            {
                item.Items.Add(new DeilveryTransationItem { Time = DateTime.Parse(o.ftime), Description = o.context });
            }

            return item;
        }

        public static bool CheckAddress(string company, string number, string address)
        {
            var ret = Query(company, number);
            if (ret.IsSigned == false)
            {
                //throw new Exception("快递单号没有被签收，不能处理");
            }

            if (ret.Items.Count < 1)
            {
                throw new Exception("快递单号没有查询到物流信息");
            }

            var city = AddressService.ParseCity(address);
            var region = AddressService.ParseRegion(address);

            if (city == null)
            {
                MessageBox.Show("未找到发货址中的市");
                return false;
            }

            if (address.Length > 15)
            {
                address = address.Substring(0, 15);
            }

            List<string> descriptions = new List<string>();


            for (int i = 0; i < 2 && i < ret.Items.Count; i++)
            {
                string source = ret.Items[ret.Items.Count - 1 - i].Description;
                if (descriptions.Contains(source) == false)
                {
                    descriptions.Add(source);
                }
            }

            string regionName = region != null ? AddressService.GetCityShortName(region.Name) : "";
            string cityName = AddressService.GetCityShortName(city.Name);
            foreach (string source in descriptions)
            {
                if (string.IsNullOrWhiteSpace(regionName) == false)
                {
                    if (source.Contains(regionName))
                    {
                        return true;
                    }
                }

                if (source.Contains(cityName))
                {
                    return true;
                }
            }

            return false;
        }

        public static float ComputeMoney(OrderPopPayType payType, string deliveryCompany, double weight, string receiverAddress)
        {
            var c = computers.FirstOrDefault(obj => obj.Accept(payType, deliveryCompany));
            if (c == null)
            {
                throw new Exception("没有指定的运费计算模板");
            }
            return (float)Math.Round(c.ComputeMoney(payType, deliveryCompany, weight, receiverAddress), 2);
        }

        private static void WriteData(ISheet sheet, params string[] datas)
        {
            var row = sheet.CreateRow(sheet.PhysicalNumberOfRows);
            foreach (var data in datas)
            {
                var cell = row.CreateCell(row.Cells.Count, NPOI.SS.UserModel.CellType.String);
                cell.SetCellValue(data);
            }
        }

        public static void Export(ExportArgs args, Mengsk.ProxyDelivery.Domain.DeliveryOut[] outs)
        {
            HSSFWorkbook workbook = new HSSFWorkbook();
            ISheet summeray = workbook.CreateSheet("总计");

            //按照支付方式分组
            var outsGroup = outs.GroupBy(obj => obj.PayType).ToArray();
            foreach (var og in outsGroup)
            {
                ISheet sheet = workbook.CreateSheet(outs[0].DeliveryCompany + (og.Key == OrderPopPayType.COD ? "-代收" : "-现付"));
                //写入头部
                WriteData(sheet, "运单号码", "计费重量", "金额", "揽收时间", "收货地址");
                foreach (var o in og)
                {
                    float weight = args.StartWeight > 0 && o.Weight > args.StartWeight && o.Weight <= args.StartWeight + args.MoreWeight ? args.StartWeight : o.Weight;
                    float computeWeight = args.Type == ExportType.COUNT ? 0.01F : weight;
                    float money = DeliveryService.ComputeMoney(o.PayType, o.DeliveryCompany, computeWeight, o.ReceiverAddress);
                    o.ERPDeliveryMoney = money;
                    WriteData(sheet, o.DeliveryNumber, weight.ToString("F2"), money.ToString("F1"), o.CreateTime.ToString("yyyy-MM-dd HH:mm:ss"), o.ReceiverAddress);
                }
                //写入本页金额
                WriteData(sheet, "本页金额总计", "", og.Select(obj => obj.ERPDeliveryMoney).Sum().ToString("F1"));
            }
            //写入总计
            var dates = outs.Select(obj => new DateTime(obj.CreateTime.Year, obj.CreateTime.Month, 1)).Distinct().ToArray();
            string dateStr = dates[0].ToString("yyyy年MM月");
            if (dates.Length > 1)
            {
                dateStr += "-" + dates.Last().ToString("yyyy年MM月");
            }
            dateStr += " 物流费用统计";
            //写入时间
            WriteData(summeray, "", dateStr);

            WriteData(summeray, "", "票数", "金额");

            //写入现付
            var onlineouts = outs.Where(obj => obj.PayType == OrderPopPayType.ONLINE).ToArray();
            if (onlineouts.Length > 0)
            {
                WriteData(summeray, "现付", onlineouts.Length.ToString(), onlineouts.Select(obj => obj.ERPDeliveryMoney).Sum().ToString("F1"));
            }
            //写入代收
            var codouts = outs.Where(obj => obj.PayType == OrderPopPayType.COD).ToArray();
            if (codouts.Length > 0)
            {
                WriteData(summeray, "代收", codouts.Length.ToString(), codouts.Select(obj => obj.ERPDeliveryMoney).Sum().ToString("F1"));
            }

            WriteData(summeray, "扣面单费", "0", "0");

            WriteData(summeray, "遗失件", "0", "0");

            WriteData(summeray, "", "总计", outs.Select(obj => obj.ERPDeliveryMoney).Sum().ToString("F1"));
            //生成遗失
            var lost = workbook.CreateSheet("遗失件明细");
            WriteData(lost, "运单号码", "商品金额", "揽收时间", "收货地址");
            using (FileStream fs = new FileStream(args.FilePath, FileMode.Create))
            {
                workbook.Write(fs);
            }
        }
    }
}
